package org.marverse.universe.properties

import scala.collection.Map
import scala.collection.mutable.HashMap
import util.Checkable
import persistance.PId
import scripting.{Type, Function, FunctionType}
import scripting.ScriptingUtil._

abstract class Property(val pid: PId) extends Function with Checkable {

}

class FunctionProperty(pid: PId) extends Property(pid) {
  
  override def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
    val body = ctx(Universe)(Properties)(this).body
    if (body.isInstanceOf[Checkable])
      body.asInstanceOf[Checkable].check
  }
  
  override def apply(argument: Any)(implicit ctx: MutableTypedMap[TypedKey, Any]) = 
    ctx(Universe)(Properties)(this).body.apply(argument)
}

object FunctionProperty {
  class State(val body: Function) {
  }
}

class PersistentProperty(pid: PId) extends Property(pid) {
  override def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
    val initial = ctx(Universe)(Properties)(this).initial
    if (initial.isInstanceOf[Checkable])
      initial.asInstanceOf[Checkable].check
  }
  
  override def apply(argument: Any)(implicit ctx: MutableTypedMap[TypedKey, Any]) = {
    val state = ctx(Universe)(Properties)(this) 
    state.values.getOrElse(argument, state.initial.apply(argument))
  }
}

object PersistentProperty {
  class State(val initial: Function) {
    private[PersistentProperty] val mutableValues = new HashMap[Any, Any]()
    val values: Map[Any, Any] = mutableValues.readOnly
  }
  
  final case class SetPersistentProperty(val property: PersistentProperty, val argument: Any, val value: Any)
  extends UniverseTransition {
    def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
      /*assertThat((property.initial.valueType.argumentType >=:: argument.valueType)(ctx), 
        "SetPP: pp arg (%s) <:: arg (%s)".format(property.initial.valueType.argumentType, argument.valueType))
      assertThat((property.initial.valueType.returnType <=:: value.valueType)(ctx),
        "SetPP: pp ret (%s) >:: value (%s)".format(property.initial.valueType.returnType, value.valueType))*/
    }
    def perform(universe: Universe) {
      universe(Properties)(property).mutableValues(argument) = value
    }
  }
  final case class ResetPersistentProperty(val property: PersistentProperty, val argument: Any) 
  extends UniverseTransition {
    def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
      /*assertThat((property.initial.valueType.argumentType >=:: argument.valueType)(ctx), 
        "ResetPP: pp arg (%s) <:: arg (%s)".format(property.initial.valueType.argumentType, argument.valueType))*/
    }
    def perform(universe: Universe) {
      universe(Properties)(property).mutableValues -= argument
    }
  }
}
